#include "stdafx.h"
#include "ByteBuffer.h"
#include <assert.h>
#include <iostream>
#include <sstream>

ByteBuffer::ByteBuffer(uint32_t size) : _rpos(0), _wpos(0), _underflow(false) {
  _buf.reserve(size);
  clear();
}

ByteBuffer::ByteBuffer(uint8_t *data, uint32_t size)
    : _rpos(0), _wpos(0), _underflow(false) {
  if (data == NULL) {
    _buf.reserve(size);
    clear();
  } else {
    _buf.reserve(size);
    clear();
    appendRaw((char *)data, size);
  }
}

ByteBuffer::~ByteBuffer() {}

void ByteBuffer::append(const std::string &str) {
  assert(str.size() <= (uint16_t)-1);
  append((uint16_t)str.size());
  for (uint32_t i = 0; i < str.length(); i++) {
    append(str[i]);
  }
}

void ByteBuffer::append(const char *data, uint32_t size) {
  assert(size <= (uint16_t)-1);
  append((uint16_t)size);
  for (uint32_t i = 0; i < size; i++)
    append(data[i]);
}

void ByteBuffer::append(const wchar_t *data, uint32_t size) {
  assert(size <= (uint16_t)-1);
  append((uint16_t)size);
  for (uint32_t i = 0; i < size; i++)
    append((uint16_t)data[i]);
}

void ByteBuffer::append(const uint8_t *data, uint32_t size) {
  assert(size <= (uint16_t)-1);
  append((uint16_t)size);
  for (uint32_t i = 0; i < size; i++)
    append(data[i]);
}

void ByteBuffer::append(ByteBuffer &buffer) {
  assert(buffer.size() <= (uint16_t)-1);
  append((uint16_t)buffer.size());
  for (uint32_t i = 0; i < buffer.size(); i++)
    append(buffer.read<uint8_t>(i));
}

void ByteBuffer::append32(const std::string &str) {
  append((uint32_t)str.size());
  for (uint32_t i = 0; i < str.length(); i++) {
    append(str[i]);
  }
}

void ByteBuffer::read32(std::string &value) {
  value.clear();

  uint32_t size = read<uint32_t>();
  for (uint32_t i = 0; i < size; i++)
    value.push_back(read<char>());
}

void ByteBuffer::appendRaw(const char *data, uint32_t size) {
  for (uint32_t i = 0; i < size; i++)
    append(data[i]);
}

void ByteBuffer::clone(ByteBuffer &buffer) {
  clear();
  for (uint32_t i = 0; i < buffer.size(); i++)
    append(buffer.read<uint8_t>(i));
}

uint32_t ByteBuffer::remaining() const { return size() - _rpos; }

void ByteBuffer::clear() {
  _rpos = 0;
  _wpos = 0;
  _buf.clear();
}

std::vector<uint8_t> &ByteBuffer::getBuffer() { return _buf; }

bool ByteBuffer::equals(ByteBuffer &other) {
  if (size() != other.size())
    return false;

  uint32_t len = size();
  for (uint32_t i = 0; i < len; i++)
    if (read<uint8_t>(i) != other.read<uint8_t>(i))
      return false;
  return true;
}

void ByteBuffer::resize(uint32_t newSize) {
  _buf.resize(newSize);
  _rpos = 0;
  _wpos = 0;
}

uint32_t ByteBuffer::size() const { return _buf.size(); }

void ByteBuffer::printHex() {
#ifdef _DEBUG
  uint32_t length = _buf.size();
  std::cout << "ByteBuffer Length: " << length << ". Hex Print" << std::endl;
  for (uint32_t i = 0; i < length; i++) {
    printf("0x%02x ", _buf[i]);
  }
  printf("\n");
#endif
}

ByteBuffer &ByteBuffer::operator<<(uint8_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(uint16_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(uint32_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(uint64_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(int8_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(int16_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(int32_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(int64_t value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(float value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(double value) {
  append(value);
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(const std::string &value) {
  append(value.c_str(), value.size());
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(const std::wstring &value) {
  append((const wchar_t *)value.c_str(), value.size());
  return *this;
}

ByteBuffer &ByteBuffer::operator<<(const char *str) {
  append(str, strlen(str));
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(uint8_t &value) {
  value = read<uint8_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(uint16_t &value) {
  value = read<uint16_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(uint32_t &value) {
  value = read<uint32_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(uint64_t &value) {
  value = read<uint64_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(int8_t &value) {
  value = read<int8_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(int16_t &value) {
  value = read<int16_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(int32_t &value) {
  value = read<int32_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(int64_t &value) {
  value = read<int64_t>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(float &value) {
  value = read<float>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(double &value) {
  value = read<double>();
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(std::string &value) {
  value.clear();

  uint16_t size = read<uint16_t>();
  for (uint16_t i = 0; i < size; i++)
    value.push_back(read<char>());
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(std::wstring &value) {
  value.clear();

  uint16_t size = read<uint16_t>();
  for (uint16_t i = 0; i < size; i++)
    value.push_back(read<wchar_t>());
  return *this;
}

ByteBuffer &ByteBuffer::operator>>(char &value) {
  value = read<char>();
  return *this;
}

uint8_t ByteBuffer::operator[](uint32_t pos) { return read<uint8_t>(pos); }
